/**
 * @file     object_pool.hpp
 * @author   WMQ
 * @date     2024/12/8
 * @brief    对象池
 */

#ifndef OBJECT_POOL_HPP
#define OBJECT_POOL_HPP

#include <cstdint>
#include <memory>

#include "ring_queue.hpp"

template <typename T>
class ObjectPool
{
public:
    /**
     * @brief 构造函数
     * @param[in] size 对象个数，大于或等于size的最小2的幂指数-1
     * @param[in] args 对象的构造参数
     */
    template <typename... Args>
    explicit ObjectPool(uint32_t size, Args &&... args) : pool_(size)
    {
        size_ = pool_.GetSize();
        object_buff_ = static_cast<T*>(::operator new(sizeof(T) * size_));
        for (uint32_t i = 0; i < size_; ++i)
        {
            T* object_ptr = object_buff_ + i;
            new (object_ptr) T(std::forward<Args>(args)...);
            pool_.MultiProducerEnQueue(&object_ptr, 1);
        }
    }

    /**
     * @brief 析构函数
     */
    virtual ~ObjectPool()
    {
        for (uint32_t i = 0; i < size_; ++i)
        {
            (object_buff_ + i)->~T();
        }
        ::operator delete(object_buff_);
    }

    /**
     * @brief 获取一个可用对象
     * @return
     *  nullptr   获取失败       \n
     *  !nullptr  对象的共享指针 \n
     * @note
     *   获取的可用对象释放的时间不能超过对象池的生命周期
     */
    std::shared_ptr<T> AcquireObject()
    {
        T* object_ptr = nullptr;
        if (!pool_.MultiConsumerDeQueue(&object_ptr, 1))
        {
            return nullptr;
        }
        std::shared_ptr<T> ptr(object_ptr, [this](T* t) {
            pool_.MultiProducerEnQueue(&t, 1);
        });
        return ptr;
    }

    /**
     * @brief 返回对象总个数
     */
    uint32_t GetSize()
    {
        return size_;
    }

private:
    uint32_t size_;      /**< 对象个数 */
    T* object_buff_;     /**< 对象数组首地址 */
    RingQueue<T*> pool_; /**< 存放可用对象地址的队列 */
};

#endif